package com.adv.ems.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONUtil;
import com.adv.ems.db.entity.SystemConfigDO;
import com.adv.ems.db.mapper.SystemConfigMapper;
import com.adv.ems.manager.SystemConfigManager;
import com.adv.ems.model.dto.TablePartitionInfoDTO;
import com.adv.ems.service.TablePartitionsMrgService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TablePartitionsMrgServiceImpl implements TablePartitionsMrgService, SmartInitializingSingleton {
    private static final String SYSTEM_CONFIG_TYPE_PARTITION_TABLE = "TABLE_PARTITION";
    @Resource
    SystemConfigManager systemConfigManager;


    @Scheduled(cron = "0 0 1 * * *")
    @Override
    public void dropAndCreateTablePartitions() {
        log.info("表分区治理------------开始");
        List<SystemConfigDO> systemConfig = systemConfigManager.selectByType(SYSTEM_CONFIG_TYPE_PARTITION_TABLE);
        if (CollectionUtil.isNotEmpty(systemConfig)) {
            systemConfig
                    .stream()
                    .map(s -> JSONUtil.toBean(s.getValue(), TablePartitionInfoDTO.class))
                    .filter(TablePartitionInfoDTO::validate)
                    .forEach(this :: tablePartitionsMrg);
        }
        log.info("表分区治理------------结束");
    }

    private void tablePartitionsMrg(TablePartitionInfoDTO info) {
        List<String> existedPartitions = systemConfigManager.getTableExistedPartitions(info.getTable());
        List<TablePartitionInfoDTO.PartitionKey> keeps = new ArrayList<>();
        List<TablePartitionInfoDTO.PartitionKey> adds = new ArrayList<>();
        initPartition(info, keeps, adds);
        List<TablePartitionInfoDTO.PartitionKey> toAdd = adds.stream().filter(ad -> !existedPartitions.contains(ad.getName())).collect(Collectors.toList());
        List<String> toDel = existedPartitions.stream().filter(e ->
                keeps.stream().noneMatch(k -> k.getName().equals(e)) && adds.stream().noneMatch(k -> k.getName().equals(e))
        ).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(toAdd)) {
            log.info("表【{}】新增分区【{}】", info.getTable(), JSONUtil.toJsonStr(toAdd));
            systemConfigManager.addPartitions(info.getTable(), toAdd);
            log.info("新增分区成功");
        }
        if (CollectionUtil.isNotEmpty(toDel)) {
            log.info("表【{}】删除分区【{}】", info.getTable(), JSONUtil.toJsonStr(toDel));
            systemConfigManager.dropPartitions(info.getTable(), toDel);
            log.info("删除分区成功");
        }
    }

    private void initPartition(TablePartitionInfoDTO info, List<TablePartitionInfoDTO.PartitionKey> keeps, List<TablePartitionInfoDTO.PartitionKey> adds) {
        String nameFormater;
        String lessValueFormater;
        TemporalUnit unit;
        if (info.getType().equals("day")) {
            nameFormater = "yyyyMMdd";
            lessValueFormater = "yyyy-MM-dd";
            unit = ChronoUnit.DAYS;
        }else if (info.getType().equals("month")) {
            nameFormater = "yyyyMM";
            lessValueFormater = "yyyy-MM-01";
            unit = ChronoUnit.MONTHS;
        }else if (info.getType().equals("year")) {
            nameFormater = "yyyy";
            lessValueFormater = "yyyy-01-01";
            unit = ChronoUnit.YEARS;
        }else {
            return;
        }
        LocalDateTime dateTime = LocalDateTime.now();
        int keepDays = Integer.parseInt(info.getValue());
        //历史
        while (keepDays > 0) {
            keepDays --;
            String lessValue = LocalDateTimeUtil.format(dateTime, lessValueFormater);
            dateTime = dateTime.minus(1, unit);
            String name = "p" + LocalDateTimeUtil.format(dateTime, nameFormater);
            TablePartitionInfoDTO.PartitionKey keep = new TablePartitionInfoDTO.PartitionKey();
            keep.setName(name);
            keep.setLessValue(lessValue);
            keeps.add(keep);
        }
        //当前+(未来+1)
        int addNum = 0;
        dateTime = LocalDateTime.now();
        while (addNum <= 1) {
            addNum ++;
            String name = "p" + LocalDateTimeUtil.format(dateTime, nameFormater);
            dateTime = dateTime.plus(1, unit);
            String lessValue = LocalDateTimeUtil.format(dateTime, lessValueFormater);
            TablePartitionInfoDTO.PartitionKey add = new TablePartitionInfoDTO.PartitionKey();
            add.setName(name);
            add.setLessValue(lessValue);
            adds.add(add);
        }
    }

    @Override
    public void afterSingletonsInstantiated() {
        dropAndCreateTablePartitions();
    }
}
